package com.zboot.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

@Configuration
public class SentinelConfig {

    //使用自己写的降级处理器
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public WebExceptionHandler sentinelGatewayExceptionHandler() {
        //这里new的就是上面写的降级处理器
        return new WebExceptionHandler() {
            private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
                ServerHttpResponse serverHttpResponse = exchange.getResponse();
                serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                byte[] datas = "{\"code\":429,\"msg\":\"请求超过最大数，请稍后再试\"}".getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
                return serverHttpResponse.writeWith(Mono.just(buffer));
            }

            @Override
            public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
                if (exchange.getResponse().isCommitted()) {
                    return Mono.error(ex);
                }
                if (!BlockException.isBlockException(ex)) {
                    return Mono.error(ex);
                }
                return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
            }

            private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
                return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
            }
        };
    }

    //使用sentinel提供的过滤器
    @Bean
    @Order(-1)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }
}
